from PyQt5.QtWidgets import QWidget, QLabel, QPushButton, QVBoxLayout
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QFont, QCursor


class QTitleLabel(QLabel):

    def __init__(self, *args):
        super(QTitleLabel, self).__init__(*args)
        self.setAlignment(Qt.AlignLeft | Qt.AlignCenter)
        self.setFixedHeight(30)


class QTitleButton(QPushButton):
    def __init__(self, *args):
        super(QTitleButton, self).__init__(*args)
        self.setFont(QFont("Webdings"))  # 特殊字体实现最大化最小化按钮
        self.setFixedWidth(40)


class QUnFrameWindow(QWidget):
    def __init__(self):
        super(QUnFrameWindow, self).__init__()
        self.setWindowFlags(Qt.FramelessWindowHint)
        self._padding = 5   # 设置边界宽度为5
        self.initTitleLabel()
        self.setWindowTitle = self._setTitleText(self.setWindowTitle)
        self.setWindowTitle("UnFrameWindow")
        self.initLayout()
        self.setMinimumWidth(250)
        self.setMouseTracking(True)
        self.initDrag()

    def initDrag(self):
        self._move_drag = False
        self._corner_drag = False
        self._bottom_drag = False
        self._right_drag = False
        pass

    def initTitleLabel(self):
        self._TitleLabel = QTitleLabel(self)
        self._TitleLabel.setMouseTracking(True)
        self._TitleLabel.setIndent(10)
        self._TitleLabel.move(0, 0)
        pass

    def initLayout(self):
        self._MainLayout = QVBoxLayout()
        self._MainLayout.setSpacing(0)
        self._MainLayout.addWidget(QLabel(), Qt.AlignLeft)
        self._MainLayout.addStretch()
        self.setLayout(self._MainLayout)
        pass

    def addLayout(self, QLayout):
        self._MainLayout.addLayout(QLayout)
        pass

    def _setTitleText(self, func):
        # 设置标题栏标签的装饰器函数
        def wrapper(*args):
            self._TitleLabel.setText(*args)
            return  func(*args)
        return wrapper

    def setTextAlignment(self, alignment):
        self._TitleLabel.setAlignment(alignment | Qt.AlignVCenter)

    def setCloseButton(self, bool_flag):
        if bool_flag :
            self._CloseButton = QTitleButton(b'\xef\x81\xb2'.decode('utf-8'), self)
            self._CloseButton.setObjectName("CloseButton") # 设置按钮的ObjectName 在qss样式中的名字
            self._CloseButton.setToolTip("关闭窗口")
            self._CloseButton.setMouseTracking(True)
            self._CloseButton.setFixedHeight(self._TitleLabel.height())
            self._CloseButton.clicked.connect(self.close)

    def setMinMaxButtons(self, bool_flag):
        if bool_flag:
            self._MinimumButton = QTitleButton(b'\xef\x80\xb0'.decode('utf-8'), self)
            self._MinimumButton.setObjectName("MinMaxButton")
            self._MinimumButton.setToolTip("最小化")
            self._MinimumButton.setMouseTracking(True)
            self._MinimumButton.setFixedHeight(self._TitleLabel.height())
            self._MinimumButton.clicked.connect(self.showMinimized)

            self._MaximumButton = QTitleButton(b'\xef\x80\xb1'.decode("utf-8"), self)
            self._MaximumButton.setObjectName("MinMaxButton")
            self._MaximumButton.setToolTip("最大化")
            self._MaximumButton.setMouseTracking(True)
            self._MaximumButton.setFixedHeight(self._TitleLabel.height())
            self._MaximumButton.clicked.connect(self._changeNormalButton)

    def _changeNormalButton(self):
        try:
            self.showMaximized()
            self._MaximumButton.setText(b'\xef\x80\xb2'.decode("utf-8"))
            self._MaximumButton.setToolTip("恢复")
            self._MaximumButton.disconnect()
            self._MaximumButton.clicked.connect(self._changeMaxButton)
        except:
            pass

    def _changeMaxButton(self):
        try:
            self.showNormal()
            self._MaximumButton.setText(b'\xef\x80\xb1'.decode("utf-8"))
            self._MaximumButton.setToolTip("最大化")
            self._MaximumButton.disconnect()
            self._MaximumButton.clicked.connect(self._changeNormalButton)
        except:
            pass

    def resizeEvent(self,  QResizeEvent):
        self._TitleLabel.setFixedWidth(self.width())
        try:
            self._CloseButton.move(self.width() - self._CloseButton.width(), 0)
        except:
            pass
        try:
            self._MinimumButton.move(self.width() - (self._CloseButton.width()+1)*3+1, 0)
        except:
            pass
        try:
            self._MaximumButton.move(self.width() - (self._CloseButton.width()+1)*2+1, 0)
        except:
            pass
        # 重新调整边界范围以备实现鼠标拖放缩放， 采用三个列表生成式生成三个列表
        self._right_rect = [QPoint(x, y) for x in range(self.width() - self._padding, self.width()+1)
                            for y in range(1, self.height() - self._padding)]
        self._bottom_rect = [QPoint(x, y) for x in range(1, self.width()-self._padding)
                             for y in range(self.height() - self._padding, self.height()+1)]
        self._corner_rect = [QPoint(x, y) for x in range(self.width() - self._padding, self.width()+1)
                             for y in range(self.height()-self._padding, self.height()+1)]

    def mousePressEvent(self, event):
        if (event.button() == Qt.LeftButton) and (event.pos() in self._corner_rect):
            # 鼠标左键点击右下角边界区域
            self._corner_drag = True
            event.accept()
        elif (event.button() == Qt.LeftButton) and (event.pos() in self._right_rect):
            #  鼠标左键点击右侧边界区域
            self._right_drag = True
            event.accept()
        elif (event.button() == Qt.LeftButton) and (event.pos() in self._bottom_rect):
            #  鼠标左键点击下侧边界区域
            self._bottom_drag = True
            event.accept()
        elif (event.button() == Qt.LeftButton) and (event.y() < self._TitleLabel.height()):
            # 鼠标左键点击标题栏区域
            self._move_drag = True
            self.move_DragPosition = event.globalPos() - self.pos()

    def mouseMoveEvent(self, event):
        # 判断鼠标位置切换鼠标手势
        if event.pos() in self._corner_rect:
            self.setCursor(Qt.SizeFDiagCursor)
        elif event.pos() in self._bottom_rect:
            self.setCursor(Qt.SizeVerCursor)
        elif event.pos() in self._right_rect:
            self.setCursor(Qt.SizeHorCursor)
        else:
            self.setCursor(Qt.ArrowCursor)

        if Qt.LeftButton and self._right_drag:
            self.resize(event.pos().x(), self.height())
            event.accept()
        elif Qt.LeftButton and self._bottom_drag:
            self.resize(self.width(), event.pos().y())
            event.accept()
        elif Qt.LeftButton and self._move_drag:
            self.move(event.globalPos() - self.move_DragPosition)
            event.accept()

    def mouseReleaseEvent(self, event):
        self._move_drag = False
        self._corner_drag = False
        self._bottom_drag = False
        self._right_drag = False


if __name__ == "__main__":
    from PyQt5.QtWidgets import QApplication
    import sys
    app = QApplication(sys.argv)
    # app.setStyleSheet(open("./UnFrameStyle.qss").read())
    window = QUnFrameWindow()
    window.setCloseButton(True)
    window.setMinMaxButtons(True)
    window.show()
    sys.exit(app.exec_())
